根據 Intel 手冊,在 64 位元模式下,Segmentation 機制通常是直接穿透的。這意味著,透過 Segmentation 機制的設定,所有邏輯地址會直接一對一對應到線性地址(也稱為 Flat Model),Segmentation 並沒有產生任何地址轉換。
在 Intel CPU 架構上,當我們討論虛擬記憶體地址時,指的是邏輯地址中的一部分。這個邏輯地址首先需要經過 Segmentation 機制轉換為線性地址,之後再經由分頁機制轉換為物理地址。
在 Segmentation 機制中,邏輯地址由兩個部分組成:segment selector
和 offset
(也稱為有效地址 effective address)。我們日常討論的虛擬地址實際上指的是這個 offset
,而 segment selector
則是一個保存在 CPU 暫存器中的數值。
segment selector
由三個欄位組成:Index
、Table Indicator (TI)
和 Requested Privilege Level (RPL)
。
我們先解釋 index,index 是 Descriptor Table 的索引值。當 MMU 執行 Segmentation 轉換時,會讀取 segment selector
暫存器,然後透過 Index 找到對應的 Descriptor Table 內的 Entry。
Descriptor Table 中的 Entry 稱為 segment descriptor
segment descriptor
中,有一個 base address
欄位,MMU 執行地址轉換時,會將這個欄位會與有效地址(offset
)相加,從而得到線性地址。這樣就完成了 Segmentation 機制的地址轉換。
另外,還有一個 limit
欄位,用來表示該段的大小。與分頁機制中固定 4K 的頁面大小不同,Segmentation 機制允許每個段的大小由 segment descriptor
定義,因此可以避免程式存取超出範圍。
那這裡就會引生出兩個問題:
segment selector
是哪個暫存器?descriptor table
的位置在哪裡?實際上,segment selector
並不是單一的暫存器,而是有多個暫存器,包括:code-segment (CS)
、data-segment (DS)
、stack-segment (SS)
,以及額外的資料段暫存器(ES
、FS
、GS
)。
為什麼會有這麼多不同的 segment selector
暫存器?原因在於它們對應到程式中不同的區段,例如程式碼段(Code)、堆疊(Stack)、資料段(Data)等。CPU 在執行不同功能時,會使用對應的段選擇器。比如,在執行指令抓取(instruction fetch)時,會使用 CS
段選擇器;而在進行一般資料讀寫時,則會使用 DS
。
因此,當我們討論一個 Process 的程式碼、堆疊(Stack)、堆積(Heap)、資料段等區塊在虛擬記憶體中的排列結構時,這些區塊經過 Segmentation 機制後,在線性地址空間中的排列方式可能會完全不同。需要注意的是,這裡指的是線性地址空間中的排列方式,至於最終如何映射到物理記憶體,還需要經過分頁機制。
當 MMU 讀取到 segment selector
中保存的 index
後,會去查找 Descriptor Table。MMU 需要從記憶體中讀取這張表。對於一個 Process 而言,MMU 實際上會看到兩張表:Global Descriptor Table (GDT) 和 Local Descriptor Table (LDT)。
在一個作業系統中,系統會有一張 GDT,並且可能會有多張或無 LDT。GDT 是整個系統共用的,而 LDT 則可能是某個 Process 專用的。在 Intel CPU 中,Global Descriptor Table Register (GDTR)
和 Local Descriptor Table Register (LDTR)
會分別指向 GDT 和 LDT 的位置,MMU 可以透過這兩個暫存器找到 GDT 和 LDT。當 Process 切換時,系統會更新 LDTR 來切換 LDT。在某些情況下,作業系統可以不使用 LDT,所有 Process 和程式碼都使用 GDT。因為還有分頁機制來提供記憶體隔離,這樣的設計是可行的。
MMU 如何知道應該查找哪一張表呢?這與 segment selector
中的 Table Indicator (TI)
欄位有關。當 TI
欄位為 0 時,表示 MMU 應查找 GDT;當為 1 時,則使用 LDT。
當 MMU 接收到一個邏輯地址空間的有效地址查詢請求後,會依序執行以下步驟:
segment selector
數值。segment selector
的 Table Indicator
欄位,判定是使用 GDT 還是 LDT(假設是 GDT)。segment selector
的 Index
,找到對應的 segment descriptor
。segment base address
,取得目標線性地址。offset
部分,最終取得物理地址。這就是 Segmentation 與 Paging 機制協同工作的完整流程。